/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
/*
 * Toplogy Viewer
 */

package cgl.narada.topology.viewer;

import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * This class represents all the clusters consisting of nodes. The cluster is 
 * second level in the node address. If node's address is 1.2.3.4 then cluster
 * id is 3
 */
public class Cluster extends Node {
    public List nodes;
    
    /**
     * Only constructor.
     */
    public Cluster(int clusterId, int pSClusterId, int pSSClusterId) {
	// form a node for this cluster. Initialize all the Ids and Position.
	super(clusterId, pSClusterId, pSSClusterId, INVALID_VALUE);
	nodes = new ArrayList();
    }

    /**
     * Adds a new node to the list. Depending upon the total number of nodes
     * in the list, recalculate the new positions for each node. 
     * @param nodeId id of a node
     */
    public void insertNode(int nodeId) {
	Node node = getNode(nodeId);
	/*
	 * Add the node only if it is absent in the list.
	 */
	if (node == null) {
	    node = new Node(nodeId, this.nodeId, this.parentClusterId,
			    this.parentSClusterId);
	    nodes.add(node);
	    repositionNodes();
	}
    }
    
    /**
     * Deletes an existing node inside the cluster. Recalculated the new
     * position for each node.
     * @param  nodeId id of the node
     * @param  nodesToBeDeleted <code>List</code> which contains the node
     *         address of a node which needs to be deleted.
     * @throws TopologyException if specified node is not found in the cluster.
     */
    public void deleteNode(int nodeId, List nodesToBeDeleted) 
	throws TopologyException {
	Iterator it = nodes.iterator();
	while ((it.hasNext()) && (nodesToBeDeleted.isEmpty())) {
	    Node node = (Node) it.next();
	    if (node.nodeId == nodeId) {
		nodesToBeDeleted.add(node);
		it.remove();
	    }
	}
	repositionNodes();
	if (nodesToBeDeleted.isEmpty()) {
	    throw new TopologyException("node absent while deletion");
	}
    }

    /** 
     * Deletes all the nodes in the cluster
     * @param  nodesToBeDeleted <code>List</code> which contains the node
     *         address of a node which needs to be deleted.
     */
    public void deleteAllNodes(List nodesToBeDeleted) {
	Iterator it = nodes.iterator();
	while (it.hasNext()) {
	    Node n = (Node) it.next();
	    nodesToBeDeleted.add(n);
	    it.remove();
	}
    }

    /**
     * Finds a node in the cluster, nearest to specified coordinates.
     * @param  x X-coordinate.
     * @param  y Y-coordinate.
     * @return <code>Node</code> null if no such node is found
     */
    public Node getNodeAtParticularCoordinates(int x, int y) {
	return PositionCalculation.getNearestNode(nodes, x, y);
    }

    /**
     * Returns a node in the cluster with specified node id
     * @param  nodeId id of a node
     * @return <code>Node</code> 
     */
    public Node getParticularNode(int nodeId) {
	Node node = getNode(nodeId);
	return node;
    }

    /**
     * Draws the cluster only if its part is visible on the screen. Draws all
     * the nodes inside it.
     * @param  g <code>Graphics</code> object for image drawing.
     * @param  limitX1 lower limit for X-coordinate
     * @param  limitY1 lower limit for Y-coordinate
     * @param  limitX2 upper limit for X-coordinate
     * @param  limitY2 upper limit for Y-coordinate
     */
    public void drawCluster(Graphics g, int limitX1, int limitY1, int limitX2, 
			    int limitY2) {
	if (this.canFitOnPanel(limitX1, limitY1, limitX2, limitY2)) {
	    this.drawNode(g, limitX1, limitY1, limitX2, limitY2);
	    Iterator itNodes = nodes.iterator();
	    while (itNodes.hasNext()) {
		Node n = (Node) itNodes.next();
		n.drawNode(g, limitX1, limitY1, limitX2, limitY2);
	    }
	}
    }

    /**
     * Gets new positions and assigns then to all nodes inside the cluster. If
     * the node is newly added then only sets its color otherwise maintains its
     * color.
     */
    public void repositionNodes() {
	List newPositions = getNewPositions();
	Iterator itPosition = newPositions.iterator();
	Iterator itNode = nodes.iterator();
	while (itNode.hasNext()) {
	    Node n = (Node) itNode.next();
	    Position p = (Position) itPosition.next();
	    if (n.nodeLocation.getRadius() == 0.0) {
		// this is new node 
		n.nodeLocation = p;
		n.nodeLocation.setColor(PositionCalculation.getNodeColor(4));
	    } else {
		// don't change the color while repositioning
		n.nodeLocation.setCenterX(p.getCenterX());
		n.nodeLocation.setCenterY(p.getCenterY());
		n.nodeLocation.setRadius(p.getRadius());
	    }
	}
    }

    /**
     * Returns <code>Node</code> in the cluster with specified id
     * @param  id id of a node.
     * @return <code>Node</code> null if no such node is found in the cluster.
     */
    private Node getNode(int id) {
	Iterator it = nodes.iterator();
	while  (it.hasNext()) {
	    Node n = (Node) it.next();
	    if (n.nodeId == id) {
		return n;
	    }
	}
	return null;
    }

    /**
     * Returns a <code>List</code> containing <code>Position</code> objects
     * for all the nodes inside cluster.
     * @return <code>List</code> of new Position objects.
     */
    private List getNewPositions() {
	int numberOfNodes = nodes.size();
	// returns empty list if there aren't any nodes in the node list
	return PositionCalculation.getNewPositions(this.nodeLocation,
						   numberOfNodes, 4);
    }

};
